﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using Tw.Trains.Domain;

namespace Tw.Trains.Console
{
    class Program
    {
        private static void Main(string[] args)
        {
            var graphs = ConfigurationManager.AppSettings.Get("graphs");
            if (string.IsNullOrWhiteSpace(graphs))
            {
                System.Console.WriteLine("no graphs");
                return;
            }
            var trainsManager = new TrainsManager(graphs);
            //1
            RouteDistanceView(trainsManager, 1, "A-B-C");
            //2
            RouteDistanceView(trainsManager, 2, "A-D");
            //3
            RouteDistanceView(trainsManager, 3, "A-D-C");
            //4
            RouteDistanceView(trainsManager, 4, "A-E-B-C-D");
            //5
            RouteDistanceView(trainsManager, 5, "A-E-D");
            //6
            Trips(trainsManager, "C", "C", new TripCondition(3, AttributeType.Stops, Operate.LessOrEquals), trips =>
            {
                var sb = new StringBuilder("6.The number of trips starting at C and ending at C with a maximum of 3 stops:\n> ");
                if (trips == null || !trips.Any())
                {
                    sb.Append("NO SUCH ROUTE");
                    System.Console.WriteLine(sb);
                    return;
                }
                trips = trips.OrderBy(t => t.TripAttribute().Distance).ToList();
                var views = TripsView(trips);
                sb.AppendFormat("{0}{1}", trips.Count, views);
                System.Console.WriteLine(sb);
            });
            //7
            Trips(trainsManager, "A", "C", new TripCondition(4, AttributeType.Stops, Operate.LessOrEquals), trips =>
            {
                var sb = new StringBuilder("7.The number of trips starting at A and ending at C with exactly 4 stops:\n> ");
                if (trips == null || !trips.Any())
                {
                    sb.Append("NO SUCH ROUTE");
                    System.Console.WriteLine(sb);
                    return;
                }
                trips = trips.Where(t => t.TripAttribute().Stops == 4).ToList();
                var views = TripsView(trips);
                sb.AppendFormat("{0}{1}", trips.Count, views);
                System.Console.WriteLine(sb);
            });
            //8
            BestTrip(trainsManager, "A", "C", trip =>
            {
                var sb = new StringBuilder("8.The length of the shortest route (in terms of distance to travel) from A to C:\n> ");
                if (trip == null)
                {
                    sb.Append("NO SUCH ROUTE");
                    System.Console.WriteLine(sb);
                    return;
                }
                var views = TripsView(new[] { trip });
                sb.AppendFormat("{0}{1}", trip.TripAttribute().Distance, views);
                System.Console.WriteLine(sb);
            });
            //9
            BestTrip(trainsManager, "B", "B", trip =>
            {
                var sb = new StringBuilder("9.The length of the shortest route (in terms of distance to travel) from B to B:\n> ");
                if (trip == null)
                {
                    sb.Append("NO SUCH ROUTE");
                    System.Console.WriteLine(sb);
                    return;
                }
                var views = TripsView(new[] { trip });
                sb.AppendFormat("{0}{1}", trip.TripAttribute().Distance, views);
                System.Console.WriteLine(sb);
            });
            //10
            Trips(trainsManager, "C", "C", new TripCondition(30), trips =>
            {
                var sb = new StringBuilder("10.The number of different routes from C to C with a distance of less than 30:\n> ");
                if (trips == null || !trips.Any())
                {
                    sb.Append("NO SUCH ROUTE");
                    System.Console.WriteLine(sb);
                    return;
                }
                trips = trips.OrderBy(t => t.TripAttribute().Stops).ToList();
                var views = TripsView(trips);
                sb.AppendFormat("{0}{1}", trips.Count, views);
                System.Console.WriteLine(sb);
            });
        }

        private static void RouteDistanceView(TrainsManager manager, int index, string route)
        {
            var distance = manager.RouteDistance(route);
            System.Console.WriteLine("{0}.The distance of the route {1}:\n> {2}", index, route,
                distance < 0 ? "NO SUCH ROUTE" : distance.ToString());
        }

        private static void Trips(TrainsManager manager, string start, string end, TripCondition condition, Action<List<TripNode>> action)
        {
            var trips = manager.Trips(start, end, condition);
            action(trips);
        }

        private static void BestTrip(TrainsManager manager, string start, string end, Action<TripNode> action)
        {
            var trip = manager.BestTrip(start, end);
            action(trip);
        }

        private static string TripsView(IEnumerable<TripNode> trips)
        {
            var list = new List<string>();
            foreach (var trip in trips)
            {
                var attr = trip.TripAttribute();
                list.Add(string.Format("\n> {0}\t-> distance:{1},stops:{2}", trip, attr.Distance, attr.Stops));
            }
            return string.Join(",", list);
        }
    }
}
